#include "label.h"
#include "director.h"
#include "sprite.h"

namespace jlib {


void TextNode::draw (const mat4 &pv, const mat4 &p, const mat4 &v, const mat4 &m) {
  debug_assert(this->_font);
  debug_assert(this->_shader && this->_shader->valid());
  if (this->_textNodeFlags & TextTextureDirty)
    this->resolveTextTexture();
  Texture *tex = this->_texture;
  if (!tex || !tex->valid())
    return;
  if (this->_textNodeFlags & VerticesAndTexCoordDirty)
    this->resolveVerticesAndTexCoord();
  tex->bind(ImageNode::u_tex);

  Shader *shader = this->_shader;
  shader->use();
  shader->u4m(ImageNode::u_pvm, pv * m);
  shader->u4f(ImageNode::u_color, this->_color);
  glEnableVertexAttribArray(ImageNode::a_position);
  glEnableVertexAttribArray(ImageNode::a_texCoord);
  glVertexAttribPointer(ImageNode::a_position, 2, GL_FLOAT, GL_FALSE, 0, this->_vertices);
  glVertexAttribPointer(ImageNode::a_texCoord, 2, GL_FLOAT, GL_FALSE, 0, this->_texCoord);
  glBlendFunc(this->_srcFactor, this->_dstFactor);
  glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
}



bool TextNode::init (const std::string &path, FileDomain domain) noexcept {
  auto root = this->getRoot();
  auto font = root->getFontManager()->get(path, domain);
  if (!font)
    return false;
  auto shader = root->getShaderManager()->get(ImageNode::ShaderName, ImageNode::VShader, ImageNode::FShader);
  if (!shader)
    return false;
  this->clear();
  this->_font = font;
  this->_shader = shader;
  return true;
}

void TextNode::clear () noexcept {
  this->_font = nullptr;
  this->_shader = nullptr;
  this->_texture = nullptr;
}



void TextNode::setShader (Shader *shader) noexcept {
  if (this->_shader == shader)
    return;
  this->_shader = shader;
}

void TextNode::setColor (const rgba &color) noexcept {
  this->_color = color;
}

void TextNode::setBlendFunc (GLenum src, GLenum dst) noexcept {
  this->_srcFactor = src;
  this->_dstFactor = dst;
}

void TextNode::setAnchor (const vec2 &anchor) noexcept {
  this->_anchor = anchor;
  this->_textNodeFlags |= VerticesAndTexCoordDirty;
}

void TextNode::setAnchor (float x, float y) noexcept {
  this->_anchor = vec2(x, y);
  this->_textNodeFlags |= VerticesAndTexCoordDirty;
}

void TextNode::setAnchorX (float x) noexcept {
  this->_anchor.x = x;
  this->_textNodeFlags |= VerticesAndTexCoordDirty;
}

void TextNode::setAnchorY (float y) noexcept {
  this->_anchor.y = y;
  this->_textNodeFlags |= VerticesAndTexCoordDirty;
}




void TextNode::setText (const std::string &text) noexcept {
  if (this->_text == text)
    return;
  this->_text = text;
  this->_textNodeFlags |= TextTextureDirty;
}

void TextNode::setConfig (const Font::Config &config) noexcept {
  this->_config = config;
  this->_textNodeFlags |= TextTextureDirty;
}

void TextNode::setAlignment (const size &alignment) noexcept {
  if (this->_config.alignment == alignment)
    return;
  this->_config.alignment = alignment;
  this->_textNodeFlags |= TextTextureDirty;
}

void TextNode::setSpacing (const size &spacing) noexcept {
  if (this->_config.spacing == spacing)
    return;
  this->_config.spacing = spacing;
  this->_textNodeFlags |= TextTextureDirty;
}

void TextNode::setTextSize (const size &textSize) noexcept {
  if (this->_config.fontSize == textSize)
    return;
  this->_config.fontSize = textSize;
  this->_textNodeFlags |= TextTextureDirty;
}

void TextNode::setAreaSize (const size &areaSize) noexcept {
  if (this->_config.area == areaSize)
    return;
  this->_config.area = areaSize;
  this->_textNodeFlags |= TextTextureDirty;

}

void TextNode::setMinAreaSize (const size &minSize) noexcept {
  if (this->_config.minArea == minSize)
    return;
  this->_config.minArea = minSize;
  this->_textNodeFlags |= TextTextureDirty;
}

void TextNode::setMaxAreaSize (const size &maxSize) noexcept {
  if (this->_config.maxArea == maxSize)
    return;
  this->_config.maxArea = maxSize;
  this->_textNodeFlags |= TextTextureDirty;
}




void TextNode::resolveTextTexture () noexcept {
  buffer buf = this->_font->draw(this->_text.c_str(), this->_config, this->_boxSize, this->_txtRect);
  if (!buf) {
    this->_texture = nullptr;
    return;
  }
  auto w = this->_txtRect.s.w;
  auto h = this->_txtRect.s.h;
  if (this->_texture) {
    size tsize = this->_texture->sizei();
    if (tsize.w != w || tsize.h != h)
      this->_texture = nullptr;
  }
  if (!this->_texture)
    this->_texture = Object::create<Texture>(w, h, GL_RGBA, GL_UNSIGNED_BYTE, buf.data<void>());
  else
    this->_texture->reload(w, h, GL_RGBA, GL_UNSIGNED_BYTE, buf.data<void>());
}


void TextNode::resolveVerticesAndTexCoord () noexcept {
  vec2 box = vec2(this->_boxSize.w, this->_boxSize.h);
  vec2 pos = vec2(this->_txtRect.p.x, this->_txtRect.p.y);
  float xmin = -this->_anchor.x * box.x + pos.x;
  float xmax = xmin + this->_txtRect.s.w;
  float ymin = -this->_anchor.y * box.y + pos.y;
  float ymax = ymin + this->_txtRect.s.h;
  this->_vertices[0] = vec2(xmin, ymin);
  this->_vertices[1] = vec2(xmax, ymin);
  this->_vertices[2] = vec2(xmin, ymax);
  this->_vertices[3] = vec2(xmax, ymax);
  this->_texCoord[0] = vec2(0.0F, 0.0F);
  this->_texCoord[1] = vec2(1.0F, 0.0F);
  this->_texCoord[2] = vec2(0.0F, 1.0F);
  this->_texCoord[3] = vec2(1.0F, 1.0F);
  this->_textNodeFlags &= ~VerticesAndTexCoordDirty;
}


} // namespace jlib
